/**
 * 
 */
package estrategias;

import java.util.Date;
import java.util.Vector;

import juegos.*;

/**
 * Esta clase implementa el metodo resuelve de una forma distinta. Se le pasa por parametro su nodo inicial y el final,
 * y se realiza una busqueda bidireccional, de un nodo hacia el otro y viceversa.
 * 
 * @author DaNieLooP
 *
 */
public class Bidireccional implements Estrategia{

	/**
	 * @param nInicial nodo inicial del juego
	 * @param nFinal nodo objetivo del juego
	 * @return Nodo nodo intermedio en que se cruzan las 2 busquedas
	 */
	public Nodo resuelve(Nodo nInicial,Nodo nFinal) {
		if (nInicial instanceof NodoGarrafas){
			return null;
		}
		int generados = 1;
		int expandidos = 0;
		Date inicio = new Date();
		boolean enc = false;
		Nodo n = null;
		Nodo nf = null;
		ColaNodos colaAbiertosInicial = new ColaNodos();
		ListaNodos listaCerradosInicial = new ListaNodos();
		ColaNodos colaAbiertosFinal = new ColaNodos();
		ListaNodos listaCerradosFinal = new ListaNodos();
		colaAbiertosInicial.inserta(nInicial);
		colaAbiertosFinal.inserta(nFinal);
		boolean f1= false;
		boolean f2 = false;
		while(!enc){
			n = colaAbiertosInicial.extrae();
			nf = colaAbiertosFinal.extrae();
			Nodo e = elementoIgual(listaCerradosInicial.getLista(),listaCerradosFinal.getLista());
			if(null!=e){
				enc = true;
				Date fin = new Date();
				float total = (fin.getTime()-inicio.getTime())/1000f;
				String saux = e.getCamino()+'\n'+"Nodos generados: "+generados+'\n'+"Nodos expandidos: "+expandidos+
				'\n'+"Tiempo transcurrido: "+total+" segundos"+'\n'+"Profundidad: "+(n.getProfundidad()+nf.getProfundidad())+'\n'+"Coste: "+(n.getCoste()+nf.getCoste());
				e.setCamino(saux);
				return e;
			}else if(listaCerradosInicial.estadoRepetido(n) || listaCerradosFinal.estadoRepetido(nf)){
				if(!listaCerradosInicial.estadoRepetido(n)){
					listaCerradosInicial.inserta(n);
					colaAbiertosInicial.insertaVector(n.generaHijos());
					expandidos++;
					generados = generados + n.generaHijos().size();
				}
				if(!listaCerradosFinal.estadoRepetido(nf)){
					listaCerradosFinal.inserta(nf);
					colaAbiertosFinal.insertaVector(nf.generaHijos());
					expandidos++;
					generados = generados + nf.generaHijos().size();
				}
			}
			else{
				expandidos = expandidos +2;
				listaCerradosInicial.inserta(n);
				listaCerradosFinal.inserta(nf);
				colaAbiertosInicial.insertaVector(n.generaHijos());
				colaAbiertosFinal.insertaVector(nf.generaHijos());
				generados = generados + nf.generaHijos().size()+n.generaHijos().size();
				
			}
		}
		return n;
	}
	/**
	 * metodo que compara dos vectores de nodos
	 * @param v1 primer vector
	 * @param v2 segundo vector
	 * @return el primer elemento comun
	 */
	public Nodo elementoIgual(Vector <Nodo>v1,Vector <Nodo>v2){
		Nodo n = null;
		for(int i=0;i<v1.size();i++){
			for(int j=0;j<v2.size();j++){
				if(v1.elementAt(i).getEstado()==v2.elementAt(j).getEstado()){
					v1.elementAt(i).setCamino(v1.elementAt(i).getCamino().concat(v2.elementAt(j).getCamino()));
					v1.elementAt(i).setCoste(v1.elementAt(i).getCoste()+v2.elementAt(j).getCoste());
					n = v1.elementAt(i);
					break;
				}
			}
		}
		return n;
	}
	/**
	 * metodo que compara dos vectores de nodos
	 * @param v1 primer vector
	 * @param v2 segundo vector
	 * @return true si son iguales
	 */
	public boolean iguales(Vector <Nodo>v1,Vector <Nodo>v2){
		return v2.containsAll(v1);
	}
	
	/**
	 * Main para probar el algoritmo
	 * @param args parametro por defecto del main
	 */
	public static void main(String[] args) {
		NodoJapos n1 = new NodoJapos();
		NodoJapos n2 = new NodoJapos();
		n2.setFinal();
		Bidireccional p = new Bidireccional();
		NodoJapos re = (NodoJapos) p.resuelve(n1,n2);
		if(re==null){
			System.out.println("no hay solucion");
		}else{
			System.out.println(re.getCamino());
		}
	}
}
